#include "../mqserver/host.hpp"
#include <gtest/gtest.h>


// using emp_map = std::unordered_map<std::string, std::string>;

class HostTest : public testing::Test
{
public:
    void SetUp() override
    {
        std::unordered_map<std::string, std::string> emp_map;
        _host = std::make_shared<mmq::VirtualHost>("host1", "./data/host1/message/", "./data/host1/host1.db");
        _host->DeclareExchange("exchange1", mmq::ExchangeType::DIRECT, true, false, emp_map);
        _host->DeclareExchange("exchange2", mmq::ExchangeType::DIRECT, true, false, emp_map);
        _host->DeclareExchange("exchange3", mmq::ExchangeType::DIRECT, true, false, emp_map);

        _host->DeclareQueue("queue1", true, true, false, emp_map);
        _host->DeclareQueue("queue2", true, true, false, emp_map);
        _host->DeclareQueue("queue3", true, true, false, emp_map);

        _host->Bind("exchange1", "queue1", "news.music.#");
        _host->Bind("exchange1", "queue2", "news.music.#");
        _host->Bind("exchange1", "queue3", "news.music.#");

        _host->Bind("exchange2", "queue1", "news.music.#");
        _host->Bind("exchange2", "queue2", "news.music.#");
        _host->Bind("exchange2", "queue3", "news.music.#");

        _host->Bind("exchange3", "queue1", "news.music.#");
        _host->Bind("exchange3", "queue2", "news.music.#");
        _host->Bind("exchange3", "queue3", "news.music.#");

        _host->BasicPublish("queue1", nullptr, "Hello World-1");
        _host->BasicPublish("queue1", nullptr, "Hello World-2");
        _host->BasicPublish("queue1", nullptr, "Hello World-3");

        _host->BasicPublish("queue2", nullptr, "Hello World-1");
        _host->BasicPublish("queue2", nullptr, "Hello World-2");
        _host->BasicPublish("queue2", nullptr, "Hello World-3");

        _host->BasicPublish("queue3", nullptr, "Hello World-1");
        _host->BasicPublish("queue3", nullptr, "Hello World-2");
        _host->BasicPublish("queue3", nullptr, "Hello World-3");
    }

    void TearDown() override
    {
        _host->Clear();
    }
public:
    mmq::VirtualHost::ptr _host;
};


TEST_F(HostTest, init_test)
{
    ASSERT_EQ(_host->ExistExchange("exchange1"), true);
    ASSERT_EQ(_host->ExistExchange("exchange2"), true);
    ASSERT_EQ(_host->ExistExchange("exchange3"), true);
    
    ASSERT_EQ(_host->ExistQueue("queue1"), true);
    ASSERT_EQ(_host->ExistQueue("queue2"), true);
    ASSERT_EQ(_host->ExistQueue("queue3"), true);

    ASSERT_EQ(_host->ExistsBind("exchange1", "queue1"), true);
    ASSERT_EQ(_host->ExistsBind("exchange1", "queue2"), true);
    ASSERT_EQ(_host->ExistsBind("exchange1", "queue3"), true);
    
    ASSERT_EQ(_host->ExistsBind("exchange2", "queue1"), true);
    ASSERT_EQ(_host->ExistsBind("exchange2", "queue2"), true);
    ASSERT_EQ(_host->ExistsBind("exchange2", "queue3"), true);
    
    ASSERT_EQ(_host->ExistsBind("exchange3", "queue1"), true);
    ASSERT_EQ(_host->ExistsBind("exchange3", "queue2"), true);
    ASSERT_EQ(_host->ExistsBind("exchange3", "queue3"), true);

    mmq::MessagePtr msg1 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg1->payload().body(), "Hello World-1");
    mmq::MessagePtr msg2 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg2->payload().body(), "Hello World-2");
    mmq::MessagePtr msg3 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg3->payload().body(), "Hello World-3");
    mmq::MessagePtr msg4 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg4.get(), nullptr);
}

TEST_F(HostTest, remove_exchange_test)
{
    _host->DeleteExchange("exchange1");
    ASSERT_EQ(_host->ExistsBind("exchange1", "queue1"), false);
    ASSERT_EQ(_host->ExistsBind("exchange1", "queue2"), false);
    ASSERT_EQ(_host->ExistsBind("exchange1", "queue3"), false);
}

TEST_F(HostTest, remove_queue_test)
{
    _host->DeleteQueue("queue1");
    ASSERT_EQ(_host->ExistsBind("exchange1", "queue1"), false);
    ASSERT_EQ(_host->ExistsBind("exchange2", "queue1"), false);
    ASSERT_EQ(_host->ExistsBind("exchange3", "queue1"), false);

    mmq::MessagePtr msg1 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg1.get(), nullptr);
}

TEST_F(HostTest, ack_message_test)
{
    mmq::MessagePtr msg1 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg1->payload().body(), "Hello World-1");
    _host->BasicAck("queue1", msg1->payload().properties().id());

    mmq::MessagePtr msg2 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg2->payload().body(), "Hello World-2");
    _host->BasicAck("queue1", msg2->payload().properties().id());
    
    mmq::MessagePtr msg3 = _host->BasicConsume("queue1");
    ASSERT_EQ(msg3->payload().body(), "Hello World-3");
    _host->BasicAck("queue1", msg3->payload().properties().id());
}


int main(int argc, char *argv[])
{
    testing::InitGoogleTest(&argc, argv);
    // testing::AddGlobalTestEnvironment(new MyTest);
    int ret = RUN_ALL_TESTS();

    return 0;
}
